/**********************************************************************************************/
/* FBL_DebugNew.h																			  */
/*                                                                       					  */
/* Copyright Paradigma, 1993-2006                                        					  */
/* All Rights Reserved.                                                 					  */
/**********************************************************************************************/
// Idea of DebugNew module is based on the Metrowerks CodeWarrior DebugNew file.
// We have greatly extend and improve this feature.
// It works now also on Windows and with MS Visual C++.
// This implemenation also have special features for Valentina Test System.
//
#ifndef DebugNew_H
#define DebugNew_H

#include <new>

/*#undef STD
#undef STD

#define STD std
#define STD std*/

#include <VShared/FBL/publ/Headers/FBL_pre_header.h>
#include <VShared/FBL/publ/Headers/FBL_Macros.h>


/**********************************************************************************************/
#define DEBUG_NEW_OFF		0	// disabled
#define DEBUG_NEW_BASIC		1	// detect overwrites, heuristically detect bad deletes
#define DEBUG_NEW_LEAKS		2	// all basic testing, plus memory leaks

#ifndef DEBUG_NEW	
	#if FBL_TEST_CODE == 1						// Default setting if not defined already. You can
		#define DEBUG_NEW	DEBUG_NEW_LEAKS 	// define DEBUG_NEW as 0,1 or 2 in your prefix or elsewhere.
	#else
		#define DEBUG_NEW	DEBUG_NEW_OFF
	#endif
#endif


/**********************************************************************************************/
#if DEBUG_NEW != 0
	// Use NEW like this:			Foo *f = NEW Foo;
	// Use NEW_NOTHROW like this:	Foo *f = NEW_NOTHROW(std::nothrow) Foo;
#if DEBUG_NEW == DEBUG_NEW_OFF
	#define NEW new
	#define NEW_NOTHROW(x) new(x)  
#elif DEBUG_NEW == DEBUG_NEW_BASIC
	#define NEW new
	#define NEW_NOTHROW(x) new(x)  
#elif DEBUG_NEW == DEBUG_NEW_LEAKS
#if FBL_MAC	
	#define NEW new(__FILE__, __LINE__, __func__)
	#define NEW_NOTHROW(x) new(x, __FILE__, __LINE__, __func__)  
#elif FBL_WIN	
	#define NEW new(__FILE__, __LINE__, __FUNCTION__)
	#define NEW_NOTHROW(x) new(x, __FILE__, __LINE__, __FUNCTION__) 
#elif FBL_UNIX
	#define NEW new(__FILE__, __LINE__, __FUNCTION__)
	#define NEW_NOTHROW(x) new(x, __FILE__, __LINE__, __FUNCTION__) 
#endif // FBL_MAC
	
		// Validate all allocated blocks, only available when leak checking is
		// enabled.
	
	void  DebugNewValidateAllBlocks();
#else
	#error DEBUG_NEW has an undefined value
#endif // DEBUG_NEW


/**********************************************************************************************/
#ifdef _MSC_VER
#pragma warning(disable: 4290)
#endif //_MSC_VER


/**********************************************************************************************/
FBL_SHARED_EXP void* operator new  (STD::size_t size,                         const char*, int, const char*) throw(STD::bad_alloc);  
FBL_SHARED_EXP void* operator new  (STD::size_t size, const STD::nothrow_t&, const char*, int, const char*) throw();  // hh 981221
FBL_SHARED_EXP void* operator new[](STD::size_t size,                         const char*, int, const char*) throw(STD::bad_alloc);  // Hsoi 980821- added
FBL_SHARED_EXP void* operator new[](STD::size_t size, const STD::nothrow_t&, const char*, int, const char*) throw();  // hh 981221

FBL_SHARED_EXP void  operator delete  (void*,                                   const char*, int, const char*) throw();
FBL_SHARED_EXP void  operator delete  (void*, const STD::nothrow_t&,           const char*, int, const char*) throw();
FBL_SHARED_EXP void  operator delete[](void*,                                   const char*, int, const char*) throw();
FBL_SHARED_EXP void  operator delete[](void*, const STD::nothrow_t&,           const char*, int, const char*) throw();


/**********************************************************************************************/
// STD operators delete:
#ifndef _MSC_VER

FBL_SHARED_EXP void operator delete(void* ptr) throw();
FBL_SHARED_EXP void operator delete(void* ptr, const STD::nothrow_t&) throw();

FBL_SHARED_EXP void operator delete[](void* ptr) throw();
FBL_SHARED_EXP void operator delete[](void* ptr, const STD::nothrow_t&) throw();

#else

void operator delete(void* ptr) throw();
void operator delete(void* ptr, const STD::nothrow_t&) throw();

void operator delete[](void* ptr) throw();
void operator delete[](void* ptr, const STD::nothrow_t&) throw();

#endif // _MSC_VER


/**********************************************************************************************/
FBL_SHARED_EXP void* fbl_new( STD::size_t size, bool is_array );
FBL_SHARED_EXP void* fbl_new( STD::size_t size, const STD::nothrow_t&,  bool is_array );

FBL_SHARED_EXP void fbl_delete(void* ptr) throw();
FBL_SHARED_EXP void fbl_delete_array(void* ptr) throw();


/**********************************************************************************************/
// Try to validate that a pointer points to a valid, uncorrupted block.
// Invokes error handler if validation fails. Will not work properly
// for C++ arrays. Does nothing when DebugNew is disabled
	
FBL_SHARED_EXP void DebugNewValidatePtr(void*);
FBL_SHARED_EXP long DebugNewGetPtrSize(void*);


/**********************************************************************************************/
#if DEBUG_NEW >= DEBUG_NEW_BASIC

	// this variable holds the number of active allocations
	
extern unsigned long gDebugNewAllocCount;

	// this variable holds the total #bytes currently allocated via operator new(),
	// not including DebugNew overhead.
	
extern unsigned long gDebugNewAllocCurr;

	// this variable holds the maximum #bytes allocated at any given point in
	// the program execution, not counting DebugNew overhead. Useful for
	// memory tuning.
	
extern unsigned long gDebugNewAllocMax;

	// this variable holds flags that control run-time behavior
	// of DebugNew. The available flags are defined in the 
	// following enum.

// this counter always grow.
// DebugNew use this counter to mark each object by its "DateTime" of creation
// to be able later sort all objects in hronological order of creation.
FBL_SHARED_EXP extern unsigned long gDebugNewTotalCount;
FBL_SHARED_EXP extern unsigned long gDebugDeleteTotalCount;
	
extern unsigned long gDebugNewFlags;


/**********************************************************************************************/
enum	  	// gDebugNewFlags bits, refer to DebugNew.doc for information
{
	dnDontFreeBlocks = 1,		// don't release free blocks back to allocator,
								// provides extended checking if leak checking enabled
	dnCheckBlocksInApplZone = 2 // valid blocks must be in application zone
};


/**********************************************************************************************/
// For every block allocated, we bump up the size to allow a header
// and trailer to be put on the block. The header has bookkeeping info
// to allow us to know if the block was probably a real allocated block,
// and size info to allow us to find the trailer. The trailer is used to
// detect overwrites.
// NOTE: magic, unlikely values are used to tag blocks. This is a heuristic
// only, since programs could legitimately be writing those same values through
// wild pointers. When leak testing is on we can do better, since we have a
// list of allocated blocks. The tag method provides reasonable checking 
// with less overhead.

struct BlockHeader
{
#if DEBUG_NEW == DEBUG_NEW_LEAKS
	BlockHeader* next;
	const char*  file;
	int			 line;		// Negative in free blocks and ingoread by leak system blocks.
	const char*	 func;
	int			 counter;	// allows to report leaks in the order of creation.
	const char*  test_func; // Valentina test system.	
#endif
	STD::size_t	size;		// size of user's block in bytes, doesn't include prefix/suffix
	STD::size_t	padSize;	// size of compiler-inserted padding, if any.
	long			tag;		// magic value identifying the block
};

struct BlockTrailer
{
	long tag;     	  // magic value at end, used to detect overwrites
};

enum BlockStatus_t	
{
	blockValid,		  		// valid allocated block
	blockFree,		  		// free block
	blockPtrNull,	  		// block pointer is NULL
	blockPtrOutOfRange, 	// block pointer outside application heap
	blockBadHeader,			// block has invalid header
	blockBadTrailer,		// block has invalid trailer
	blockNotInList,			// block appears valid, but is not in block list (leak checking only)
	blockFreeOverwritten, 	// dnDontFreeBlocks enabled, zapped free block was overwritten
	blockDeleteNotMatch		// called new and delete[] or new[] and delete
};	

	
/**********************************************************************************************/
// For use with class-specific operator new and operator delete.
// Allows use of DebugNew's block checking with your own allocator.
//
// Call DebugNewDoAllocate from your operator new, passing 
// in the file, line, a pointer to a function that
// allocates the necessary amount of memory, and whether this
// is an array new or not. To actually 
// track the file and line you must also provide:
//   void* operator new(size_t size, const char*, int);  
// for the class. Otherwise pass NULL for the file and
// zero for the line number.
//
// Call DebugNewDoFree from your operator delete, passing in
// a pointer to a function to deallocate the memory.

FBL_SHARED_EXP void* DebugNewDoAllocate(STD::size_t size, const char* file, int line, const char* func,
						void* (*alloc_func)(STD::size_t size), bool is_array = false);
FBL_SHARED_EXP void* DebugNewDoAllocate(STD::size_t size, const char* file, int line, const char* func,
						void* (*alloc_func)(STD::size_t size), const STD::nothrow_t&, bool is_array = false);  // hh 981221
FBL_SHARED_EXP void  DebugNewDoFree(void* ptr, void (*free_func)(void* ptr), bool is_array = false);

	// Call to write memory leak tracking status to a file called
	// "leaks.log" in the application directory. Returns the
	// number of leaks.
	
FBL_SHARED_EXP long DebugNewReportLeaks();

	// This method allow you tell to leak system to ignore some allocation.
	// This is useful for e.g. Singlentons, which can be born during testing,
	// so leak system report them as leaks. But this is not correct. They are not leaks.
FBL_SHARED_EXP void DebugNewWatchLeaksStart( void );
FBL_SHARED_EXP void DebugNewWatchLeaksStop( void );

	// Call to tell DebugNew to ignore any currently allocated
	// blocks in the leak report. Useful at app startup to ignore
	// memory allocated at startup that doesn't get explicitly
	// freed.
	
FBL_SHARED_EXP void DebugNewForgetLeaks();

FBL_SHARED_EXP void BuildSortedArrayOfLeaks( 
		int inLeaksCount, BlockHeader**& outArray, unsigned long inCounter = 0 );

FBL_SHARED_EXP void FreeSortedArrayOfLeaks( BlockHeader** outArray );

FBL_SHARED_EXP unsigned long CountLeaks( 
		unsigned long& count, 
		unsigned long& totalAlloc, 
		unsigned long& bytesLeaked,
		unsigned long inCounter = 0 );


/**********************************************************************************************/
// You can optionally provide an error handler to be called when
// errors are detected. The default routine just calls DebugStr.
// Call DebugNewSetErrorHandler to set handler, it returns the
// old handler.
//	
typedef void (*DebugNewErrorHandler_t)(short);

DebugNewErrorHandler_t	DebugNewSetErrorHandler(DebugNewErrorHandler_t newHandler);

enum DebugNewError_t			// error codes passed to error handler
{
	dbgnewNullPtr,				// validate called with NULL pointer
	dbgnewTooManyFrees,			// #deletes doesn't match #news, too many deletes
	dbgnewPointerOutsideHeap,	// validate or free call for pointer outside application heap
	dbgnewFreeBlock,			// validate or delete called for free block
	dbgnewBadHeader,			// validate or delete called for block with bad header. 
								// Bad ptr or overwritten header, or delete[] called on
								// block allocated with new.
	dbgnewBadTrailer,			// validate or delete called with block whose trailer was overwritten
	dbgnewBlockNotInList,		// validate or delete called with block with valid header/trailer, 
								// but block is not in block list (internal error?)
	dbgnewFreeBlockOverwritten, // dnDontFreeBlocks was enabled, and a free block was
								// modified. Usually indicates a write through a dangling pointer.
	dbgnewMismatchedNewDelete	// delete called for memory allocated with new[],
								// (or perhaps delete[] on new).
};	

#endif  // DEBUG_NEW >= DEBUG_NEW_BASIC


#pragma mark -


/**********************************************************************************************/
// DebugNew have 2 functions to control leaks. 
// To simplify syntax of their usage and avoid a lots of #ifdef, we define here
// empty macros for this methods. In case Leak system is disabled, we get nothing in code.
// 
#if DEBUG_NEW < DEBUG_NEW_LEAKS

	#define DebugNewWatchLeaksStart()
	#define DebugNewWatchLeaksStop()

#endif // DEBUG_NEW < DEBUG_NEW_LEAKS


/**********************************************************************************************/
// Small utility class to simplify syntax even more for stop/start leaks watching.
//
class StWatchLeakStopper
{
	public:  StWatchLeakStopper( void ) { DebugNewWatchLeaksStop(); }
	public: ~StWatchLeakStopper( void ) { DebugNewWatchLeaksStart(); }	
};


/**********************************************************************************************/
#endif

#include <VShared/FBL/publ/Headers/FBL_post_header.h>

#endif	// DebugNew_H
